package com.moxie.ocr.ocr.card;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.jph.takephoto.model.TImage;
import com.jph.takephoto.model.TResult;

import com.moxie.ocr.R;
import com.moxie.ocr.network.MXLicDownloadManager;
import com.moxie.ocr.ocr.base.MXBaseTakePhotoActivity;
import com.moxie.ocr.ocr.base.MXGlobalVar;
import com.moxie.ocr.ocr.idcard.IDCardRecognizer;
import com.moxie.ocr.ocr.idcard.MXIDCardScan;
import com.moxie.ocr.ocr.idcard.MXOCRResult;
import com.moxie.ocr.ocr.presenter.MXCardPresenter;
import com.moxie.ocr.ocr.utils.MXConstants;
import com.moxie.ocr.ocr.utils.MXLightManager;
import com.moxie.ocr.ocr.utils.MXLog;
import com.moxie.ocr.ocr.utils.MXSDCardUtils;
import com.moxie.ocr.ocr.utils.MXScreenUtils;
import com.moxie.ocr.ocr.utils.MXWindowToast;
import com.moxie.ocr.ocr.utils.Util;
import com.moxie.ocr.ocr.view.PreviewLayout;
import com.moxie.ocr.ocr.view.OverlayView;




import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.Field;


public abstract class CardActivity extends MXBaseTakePhotoActivity implements SurfaceHolder.Callback, MXCardScanListener, MXLightManager.LightSensorListener {

    private static final String TAG = CardActivity.class.getSimpleName();

    /**
     * 生产环境
     */
    public static final String KEY_PRODUCTION_MODE = "key_production_mode";

    private boolean isProductionMode = true;

    /**
     * 默认的扫描框颜色
     */
    private static final int SCAN_RECT_DEFAULT_COLOR = 0xffffffff;
    /**
     * 默认的背景颜色
     */
    private final int BACKGROUND_DEFAULT_COLOR = 0xbb000000;
    /**
     * 扫描框位置上下偏移量设置
     */
    public static int SCANRECTOFFSET = 0;


    /**
     * 扫描界面返回按钮背景图片资源ID
     */
    public static final String EXTRA_BACK_DRAWABLE_ID = "com.moxie.card.backDrawable";

    /**
     * 扫描界面标题
     */
    public static final String EXTRA_SCAN_TITLE = "com.moxie.card.title";

    /**
     * 扫描界面标题标题部分右侧图标按钮---横屏切换到竖屏资源ID
     */
    public static final String EXTRA_TITLE_RIGHT_HORIZONTAL_TO_VERTICAL_DRAWABLE_ID = "com.moxie.card.title.right.to.vertical";

    /**
     * 扫描界面标题标题部分右侧图标按钮---横屏切换到竖屏资源ID
     */
    public static final String EXTRA_TITLE_RIGHT_VERTICAL_TO_HORIZONTAL_DRAWABLE_ID = "com.moxie.card.title.right.to.horizontal";

    /**
     * 扫描框颜色
     */
    public static final String EXTRA_SCAN_GUIDE_COLOR = "com.moxie.card.guideColor";

    /**
     * 背景颜色
     */
    public static final String EXTRA_SCAN_BACKGROUND_COLOR = "com.moxie.card.backgroundColor";

    /**
     * 获取扫描结果
     */
    public static final String EXTRA_SCAN_RESULT = "com.moxie.card.scanResult";

    /**
     * 用于传入保存预览图像的频率的key（单位s）
     */
    public static final String EXTRA_PREVIEW_TIME_GAPS = "com.moxie.card.preview.time.gaps";

    /**
     * 用于传入保存预览图像的路径的key
     */
    public static final String EXTRA_PREVIEW_STOREAGE_PATH = "com.moxie.card.preview.storage.path";

    /**
     * 用于传入保存预览图像的最大个数的key
     */
    public static final String EXTRA_PREVIEW_SAVED_NUM = "com.moxie.card.preview.saved.num";

    /**
     * 设置扫描界面提示文字<br>
     * 输入类型为String，用\n换行
     */
    public static final String EXTRA_SCAN_TIPS = "com.moxie.card.scanTips";

    /**
     * 用于传入扫描偏移量，参考SCANRECTOFFSET
     */
    public static final String EXTRA_SCAN_RECT_OFFSET = "com.moxie.card.scanRectOffset";

    /**
     * 用于传入当前的识别方向  true---垂直，false-水平
     */
    public static final String EXTRA_SCAN_CARD_VERTICAL = "com.moxie.card.vertical";

    /**
     * 设置需要输出原始图片<br>
     * 输入类型为boolean，true表示要输出，false表示不需要输出<br>
     * 可以在{@link Activity#onActivityResult(int, int, Intent)}中使用<br>
     * data.getByteArrayExtra(CardActivity.EXTRA_CARD_IMAGE)获取JPEG字节数组
     */
    public static final String EXTRA_CARD_IMAGE = "com.moxie.card.image";

    /**
     * 设置需要输出裁剪之后的图片<br>
     * 输入类型为boolean，true表示要输出，false表示不需要输出<br>
     * 可以在{@link Activity#onActivityResult(int, int, Intent)}中使用<br>
     * data.getByteArrayExtra(CardActivity.EXTRA_CARD_IMAGE_RECTIFIED)获取JPEG字节数组
     */
    public static final String EXTRA_CARD_IMAGE_RECTIFIED = "com.moxie.card.rectifiedImage";

    /**
     * 需要双面扫描时使用，设置需要输出裁剪之后的身份证正面图片<br>
     * 输入类型为boolean，true表示要输出，false表示不需要输出<br>
     * 可以在{@link Activity#onActivityResult(int, int, Intent)}中使用<br>
     * data.getByteArrayExtra(CardActivity.EXTRA_CARD_IMAGE_FRONT_RECTIFIED)获取JPEG字节数组
     */
    public static final String EXTRA_CARD_IMAGE_FRONT_RECTIFIED = "com.moxie.card.rectifiedImageFront";

    /**
     * 需要双面扫描时使用，设置需要输出的身份证正面原图<br>
     * 输入类型为boolean，true表示要输出，false表示不需要输出<br>
     * 可以在{@link Activity#onActivityResult(int, int, Intent)}中使用<br>
     * data.getByteArrayExtra(CardActivity.EXTRA_CARD_IMAGE_FRONT_RECTIFIED)获取JPEG字节数组
     */
    public static final String EXTRA_CARD_IMAGE_FRONT = "com.moxie.card.imageFront";

    /**
     * 设置扫描界面的方向<br>
     * {@link #ORIENTATION_PORTRAIT}<br>
     * {@link #ORIENTATION_LANDSCAPE_LEFT}<br>
     * {@link #ORIENTATION_LANDSCAPE_RIGHT}<br>
     */
    public static final String EXTRA_SCAN_ORIENTATION = "com.moxie.card.orientation";

    public static final String EXTRA_SCAN_LINE_STATUS = "com.moxie.card.scan.line.status";

    /**
     * 是否需要卡片在框内才可以识别的传入key
     */
    public static final String EXTRA_SCAN_IS_IN_FRAME = "com.moxie.card.scan.is.in.frame";

    /**
     * 设置扫描的超时时间，单位秒
     */
    public static final String EXTRA_SCAN_TIME_OUT = "com.moxie.card.scan.time.out";

    public static final String EXTRA_SCAN_AUTO_FOCUS = "com.moxie.card.scan.auto.focus";

    public static final String EXTRA_SCAN_MANUAL_RECOGNIZE = "com.moxie.card.scan.auto.recognize";


    /**
     * 卡片信息返回成功
     */
    public static final int RESULT_CARD_INFO = 1;
    /**
     * 相机无法使用
     */
    public static final int RESULT_CAMERA_NOT_AVAILABLE = 2;
    /**
     * 初始化失败，可能不兼容或模型不匹配
     */
    public static final int RESULT_RECOGNIZER_INIT_FAILED = 3;

    /**
     * 扫描失败，扫描超时
     */
    public static final int RESULT_RECOGNIZER_FAIL_SCAN_TIME_OUT = 4;

    /**
     * 面对屏幕，设备头部朝上
     */
    public static final int ORIENTATION_PORTRAIT = 1;
    /**
     * 面对屏幕，设备头部朝右
     */
    public static final int ORIENTATION_LANDSCAPE_RIGHT = 2;
    // TODO-Alen Portrait upside down is not working, make it public after we've
    // fixed this issue
    public static final int ORIENTATION_PORTRAIT_UPSIDE_DOWN = 3;
    /**
     * 面对屏幕，设备头部朝左
     */
    public static final int ORIENTATION_LANDSCAPE_LEFT = 4;

    /**
     * 扫描的默认超时时间，30s
     */
    private static final int LF_SCAN_TIME_OUT_DEFAULT = 30;

    /**
     * 当前识别是否是垂直方向
     */
    protected boolean mCardOrientationVertical = false;

    /**
     * 预览view
     */
    private PreviewLayout mPlytPreview;

    /**
     * 预览页面覆盖层
     */
    private View mOverlay;

    private MXCardPresenter mCardPresenter;

    /**
     * 扫描区域大小
     */
    private Rect mCardScanRect;

    /**
     * 当前识别的方向
     */
    private int mFrameOrientation = ORIENTATION_PORTRAIT ;

    /**
     * 默认的背景颜色
     */
    private int mBackGroundColor;

    /**
     * 默认的扫描框颜色
     */
    private int mScanRectColor;

    /**
     * OCR扫描类
     */
    private CardScanner mCardScanner;

    /**
     * 预览覆盖层
     */
    private FrameLayout mPreviewFrameLayout;

    /**
     * 标题右侧按钮（或文本）
     */
    protected ImageView mIvTitleRight;
    protected TextView mTvTitleRight;

    /**
     * 开启闪光灯按钮
     */
    protected CheckBox mCbFlashLight;

    /**
     * 拍摄按钮
     * */
    protected TextView mTvCapture;

    protected TextView mTvDebug;

    /**
     * 是否开启扫描光标，默认开启
     */
    private boolean mIsStartScanLine;

    /**
     * 标题右边图标，跳转到竖屏
     */
    private int mRightTitleToVerticalResId;

    /**
     * 标题右边图标，跳转到横屏
     */
    private int mRightTitleToHorizontalResId;

    private Handler mMainHandler;

    /**
     * 是否需要卡片在框内才可以识别，默认true
     */
    private boolean mIsInFrame = true;

    /**
     * 扫描的超时时间
     */
    private int mScanTimeOut;

    private boolean mScanIsAutoFocus;

    protected boolean mScanIsManualRecognize;

    private MXLightManager mMXLightManager;

    private boolean mIsCanStartFlashWhenLightChange = true;

    /**
     * 采用选择照片（相册）或手动拍照时 获取图片
     * */
    private ImageView mIvTest;

    @Override
    @SuppressLint("InlinedApi")
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.layout_card_activity_main);
        MXLog.i(TAG, "onCreate");
        mMainHandler = new Handler();
        initPresenter();
        getIntentData();
        initOCRSDK();
        try {
            createCardScan();
            initView();
            initOrientation();
        } catch (Exception e) {
            handleGeneralExceptionError(e);
        }
        MXScreenUtils.initialize(this);
    }





    private void initOCRSDK() {
        //初始化OCR SDK的License路径
        MXIDCardScan.getInstance(this).initLicensePath( MXSDCardUtils.getSDCardBaseDir() + File.separator + MXConstants.LICENSE_MIDDLE_PATH + File.separator + MXConstants.LICENSE_NAME, MXConstants.LICENSE_NAME);
        int remainingDays = MXIDCardScan.getInstance(this).getRemainingDays();
        if (!MXIDCardScan.getInstance(this).checkLicenseValid() || remainingDays < MXConstants.DAYS_BEFORE_LIC_EXPIRED) {
            // 通过initWithProductionMode设置环境，true为线上环境，false为生产环境，默认是false
            // 注意上线产品设置为线上环境
            // 通过downLoadLic替换过期证书
            isProductionMode = getIntent().getBooleanExtra(KEY_PRODUCTION_MODE,false);
            MXLicDownloadManager.getInstance(this).initWithProductionMode(isProductionMode).downLoadLic();
        }
    }




    private void initPresenter() {
        mCardPresenter = new MXCardPresenter();
    }

    private void initSensor() {
        mMXLightManager = new MXLightManager(this);
    }

    /**
     * 初始化布局
     */
    private void initView() {
        mIvTest = (ImageView) findViewById(R.id.id_iv_src_bmp);
        mCbFlashLight = (CheckBox) findViewById(R.id.id_cb_flash);
        mTvDebug = (TextView) findViewById(R.id.id_tv_light);
        initPreviewView();
        initBackButton();
        initTitle();
        initTitleRightBtn();


        // 闪光灯
        mCbFlashLight.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                onSwitchCameraFlashLight(isChecked);
            }
        });

        // 拍照
        mTvCapture = (TextView) findViewById(R.id.id_tv_capture);
        mTvCapture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTvCapture.setClickable(false);
                Bitmap bmp = mCardScanner.takePicture();
//                mIvTest.setImageBitmap(bmp);
                MXGlobalVar.setCardBitmap(bmp);
//                startActivity(new Intent(CardActivity.this, ConfirmPictureActivity.class));      //Test
                processManualRecognize();
            }
        });

        if (mCardScanner != null) {
            mCardScanner.setTvDebug(mTvDebug);
        }
    }



    /**
     * 初始化预览界面
     */
    private void initPreviewView() {
        //获取扫描卡位置上下偏移量
        SCANRECTOFFSET = getIntent().getIntExtra(EXTRA_SCAN_RECT_OFFSET, 0);

        mPlytPreview = (PreviewLayout) findViewById(R.id.id_plyt_preview);

        int[] previewSize = mCardPresenter.getPreviewSize(mFrameOrientation, mCardScanner.getPreviewWidth(),
                mCardScanner.getPreviewHeight());
        if (previewSize != null) {
            mPlytPreview.setPreviewSize(previewSize[0], previewSize[1]);
        }
        clearOverlayView();
        initOverlayView();
        mPlytPreview.getSurfaceHolder().addCallback(this);
    }

    /**
     * 初始化返回按钮
     */
    private void initBackButton() {
        //返回按钮
        ImageView ivBack = (ImageView) findViewById(R.id.id_iv_back);
        int backDrawableID = getIntent().getIntExtra(EXTRA_BACK_DRAWABLE_ID, 0);

        if (backDrawableID != 0) {
            ivBack.setImageResource(backDrawableID);
            ivBack.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    onClickBack(view);
                }
            });
        }
    }


    /**
     * 返回按钮点击事件
     *
     * @param view
     */
    protected void onClickBack(View view) {
        finish();
    }

    /**
     * 初始化标题
     */
    protected void initTitle() {
        TextView tvTitle = (TextView) findViewById(R.id.id_tv_title);
        String title = getIntent().getStringExtra(EXTRA_SCAN_TITLE);
        tvTitle.setText(title);
    }

    /**
     * 初始化标题栏右侧按钮图标
     */
    protected void initTitleRightBtn() {
        mIvTitleRight = (ImageView) findViewById(R.id.id_iv_right);
        mTvTitleRight = (TextView) findViewById(R.id.id_tv_right);
        refreshRightTitleBtnView();
        // （银行卡）横竖卡选择
        mIvTitleRight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickRotateCardBtn(v);
            }
        });

        // 点击"相册"
        mTvTitleRight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onClickPickPictureBtn(view);
            }
        });
    }

    private void initLightManager() {
        // 判断下方是显示手电筒还是"拍摄"按钮
        if(!mScanIsManualRecognize) {
            // 自动识别时 显示闪光灯
            mCbFlashLight.setVisibility(View.VISIBLE);
            showFlashLightButton();

            if (mMXLightManager == null) {
                mMXLightManager = new MXLightManager(this);
            }
            mMXLightManager.registerLightSensorListener(this);
        } else {
            // 非自动识别时，显示"拍摄"
            mTvCapture.setVisibility(View.VISIBLE);
        }
    }

    private void destroyLightManager() {
        if (mMXLightManager != null) {
            mMXLightManager.destroy();
        }
    }

    protected void onSwitchCameraFlashLight(boolean isStartFlash) {
        if (isStartFlash) {
            mIsCanStartFlashWhenLightChange = false;
        }
        if (mCardScanner != null) {
            mCardScanner.switchCameraFlashLight(isStartFlash);
        }
    }

    protected int getRightButtonResId() {
        return mCardOrientationVertical ? mRightTitleToHorizontalResId : mRightTitleToVerticalResId;
    }

    protected void refreshRightTitleBtnView() {
    }

    /**
     * 标题栏右侧"相册"按钮点击事件
     */
    protected void onClickPickPictureBtn(View view) {
        // 非自动模式下 点击右侧"相册" 会跳转到本地相册
        pickPictureFromAlbum();
    }

    /**
     * 只用于银行卡的横竖卡（由银行卡子类重写完成）
     * */
    protected void onClickRotateCardBtn(View view) {}

    /**
     * 初始化预览界面覆盖层
     */
    protected void initOverlayView() {
        mPreviewFrameLayout = (FrameLayout) findViewById(R.id.id_vs_overlay);

        SurfaceView sv = mPlytPreview.getSurfaceView();
        if (sv == null) {
            return;
        }

        mCardScanRect = getCardScanRect(mFrameOrientation, mCardOrientationVertical, sv.getWidth(), sv.getHeight());

        //设置扫描框位置上下偏移量
        mCardScanRect.top += SCANRECTOFFSET;
        mCardScanRect.bottom += SCANRECTOFFSET;

        // 调整卡的显示比例
//        adjustCardScanRect(mCardScanRect, sv.getWidth(), sv.getHeight());

        if (mCardScanner != null) {
            // mCardScanner.getPreviewWidth() = 1920, sv.getWidth() = 1080, sv.getHeight() = 1920, scale = 1
            float scale = getCropRectScale(mCardScanner.getPreviewWidth(), sv.getWidth(), sv.getHeight());

            Rect cropRect = new Rect();
            cropRect.left = (int) (mCardScanRect.left * scale);
            cropRect.right = (int) (mCardScanRect.right * scale);
            cropRect.top = (int) (mCardScanRect.top * scale);
            cropRect.bottom = (int) (mCardScanRect.bottom * scale);

            // left = 54, top = 656, right = 1026, bottom = 1263
            mCardScanner.setCardScanRect(cropRect);
        }

        mCardScanRect.top += sv.getTop();
        mCardScanRect.bottom += sv.getTop();
        mCardScanRect.left += sv.getLeft();
        mCardScanRect.right += sv.getLeft();

        mOverlay = createOverlayView();

        if (mOverlay instanceof OverlayView) {
            ((OverlayView) mOverlay).setPreviewAndScanRect(new Rect(sv.getLeft(), sv.getTop(), sv.getRight(), sv.getBottom()),
                    mCardScanRect);
        }

        addOverlayView(mOverlay);
//        showFlashLightButton();
    }

    /**
     * 如果子类对扫描框有特殊要求时 可自行调整扫描框
     * 银行卡 竖卡&拍照识别时需要调整一下
     * 身份证目前上不需要
     * */
    protected void adjustCardScanRect(Rect cardScanRect, int svWidth, int svHeight) {}

    /**
     * 从相册选图
     * */
    private void pickPictureFromAlbum() {
        int aspectX = 16, aspectY = 10;
        Display display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

        // 手机方向均是竖向
        if(mCardOrientationVertical) {
            // 拍摄竖卡时，裁剪框应该使用竖向裁剪框
            int outputY = display.getHeight();
            int outputX = (int) ((outputY * aspectY + 0.0f) / aspectX);
            getTakePhoto().onPickFromGalleryWithCrop(createTmpUri(), getCropOptions(outputX, outputY,
                    aspectY, aspectX));
        } else {
            // 拍摄横卡时，裁剪框应该使用横向裁剪框
            int outputX = display.getWidth();
            int outputY = (int) ((outputX * aspectY + 0.0f) / aspectX);
            getTakePhoto().onPickFromGalleryWithCrop(createTmpUri(), getCropOptions(outputX, outputY,
                    aspectX, aspectY));
        }
    }

    /**
     * 手动拍摄含卡图片
     * */
    @Override
    public void takeSuccess(TResult result) {
        super.takeSuccess(result);

        // 由于截图成功后 Camera又一次被打开了 所以需要重置相机状态为未释放状态
        mCardScanner.setCameraRelease(false);

        TImage image = result.getImage();
        if(image != null) {
            InputStream inputStream = null;
            try {
                inputStream = new FileInputStream(new File(image.getOriginalPath()));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }

            Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
            // 需要压缩 否则模型识别不了
            Matrix matrix = new Matrix();
            matrix.setScale(0.5f, 0.5f);
            Bitmap compressBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

            MXGlobalVar.setCardBitmap(compressBmp);
            processManualRecognize();
        }
    }



    protected void processManualRecognize() {}

    private void showFlashLightButton() {
        switch (mFrameOrientation) {
            case CardActivity.ORIENTATION_LANDSCAPE_LEFT:
            case CardActivity.ORIENTATION_LANDSCAPE_RIGHT:
                showFlashBtnInRight();
                break;
            case CardActivity.ORIENTATION_PORTRAIT:
            case CardActivity.ORIENTATION_PORTRAIT_UPSIDE_DOWN:
            default:
                showFlashBtnInBottom();
                break;
        }
    }

    private void showFlashBtnInRight() {
        RelativeLayout.LayoutParams resultParams = null;
        LayoutParams layoutParams = mCbFlashLight.getLayoutParams();
        if (layoutParams instanceof RelativeLayout.LayoutParams) {
            resultParams = (RelativeLayout.LayoutParams) layoutParams;
        }
        if (resultParams != null) {

            int right = mCardScanRect.right;

            SurfaceView sv = mPlytPreview.getSurfaceView();
            int width = sv.getWidth();

            int remainMiddle = (width - right) / 2;

            int flashBtnRight = remainMiddle - MXScreenUtils.dip2px(25);

            resultParams.width = MXScreenUtils.dip2px(50);
            resultParams.height = MXScreenUtils.dip2px(50);
            resultParams.rightMargin = Math.abs(flashBtnRight);
            resultParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            resultParams.addRule(RelativeLayout.CENTER_VERTICAL);

            mCbFlashLight.setLayoutParams(resultParams);
            mCbFlashLight.setVisibility(View.VISIBLE);
        }
    }

    private void showFlashBtnInBottom() {

        RelativeLayout.LayoutParams resultParams = null;
        LayoutParams layoutParams = mCbFlashLight.getLayoutParams();
        if (layoutParams instanceof RelativeLayout.LayoutParams) {
            resultParams = (RelativeLayout.LayoutParams) layoutParams;
        }
        if (resultParams != null) {

            int bottom = mCardScanRect.bottom;

            SurfaceView sv = mPlytPreview.getSurfaceView();
            int height = sv.getHeight();

            int remainMiddle = (height - bottom) / 2;

            int flashBtnBottom = remainMiddle - MXScreenUtils.dip2px(25);

            resultParams.width = MXScreenUtils.dip2px(50);
            resultParams.height = MXScreenUtils.dip2px(50);
            resultParams.bottomMargin = Math.abs(flashBtnBottom);
            resultParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
            resultParams.addRule(RelativeLayout.CENTER_HORIZONTAL);

            mCbFlashLight.setLayoutParams(resultParams);
            mCbFlashLight.setVisibility(View.VISIBLE);
        }
    }

    private float getCropRectScale(int previewWidth, int surfaceWidth, int surfaceHeight) {
        float scale = 1;
        switch (mFrameOrientation) {
            case ORIENTATION_LANDSCAPE_LEFT:
            case ORIENTATION_LANDSCAPE_RIGHT:
                scale = (previewWidth + 0.0f) / surfaceWidth;
                break;
            case ORIENTATION_PORTRAIT:
            case ORIENTATION_PORTRAIT_UPSIDE_DOWN:
            default:
                scale = (previewWidth + 0.0f) / surfaceHeight;
                break;
        }
        return scale;
    }

    /**
     * 清除预览覆盖层view
     */
    protected void clearOverlayView() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mPreviewFrameLayout != null) {
                    mPreviewFrameLayout.removeAllViews();
                }
            }
        });
    }

    /**
     * 添加到预览覆盖层
     *
     * @param view
     */
    protected void addOverlayView(final View view) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                        FrameLayout.LayoutParams.MATCH_PARENT);
                mPreviewFrameLayout.removeView(view);
                mPreviewFrameLayout.addView(view, layoutParams);
            }
        });
    }

    /**
     * 获取扫描区域大小
     *
     * @param width
     * @param height
     * @return
     */
    private Rect getCardScanRect(int frameOrientation, boolean cardOrientationVertical, int width, int height) {
        Rect rect = new Rect();
        if (mCardPresenter != null) {
            rect = mCardPresenter.getCardScanRect(frameOrientation, cardOrientationVertical, width, height);
        }
        return rect;
    }

    /**
     * 获取数据
     */
    private void getIntentData() {
        mCardOrientationVertical = getIntent().getBooleanExtra(EXTRA_SCAN_CARD_VERTICAL, false);
//        mFrameOrientation = getIntent().getIntExtra(EXTRA_SCAN_ORIENTATION, ORIENTATION_PORTRAIT);

        mBackGroundColor = getIntent().getIntExtra(EXTRA_SCAN_BACKGROUND_COLOR, BACKGROUND_DEFAULT_COLOR);
        mScanRectColor = getIntent().getIntExtra(EXTRA_SCAN_GUIDE_COLOR, SCAN_RECT_DEFAULT_COLOR);
        mIsStartScanLine = getIntent().getBooleanExtra(EXTRA_SCAN_LINE_STATUS, true);

        mRightTitleToHorizontalResId = getIntent().getIntExtra(EXTRA_TITLE_RIGHT_VERTICAL_TO_HORIZONTAL_DRAWABLE_ID, 0);
        mRightTitleToVerticalResId = getIntent().getIntExtra(EXTRA_TITLE_RIGHT_HORIZONTAL_TO_VERTICAL_DRAWABLE_ID, 0);

        mIsInFrame = getIntent().getBooleanExtra(EXTRA_SCAN_IS_IN_FRAME, true);
        mScanTimeOut = getIntent().getIntExtra(EXTRA_SCAN_TIME_OUT, LF_SCAN_TIME_OUT_DEFAULT);
        mScanIsAutoFocus = getIntent().getBooleanExtra(EXTRA_SCAN_AUTO_FOCUS, true);
        mScanIsManualRecognize = getIntent().getBooleanExtra(EXTRA_SCAN_MANUAL_RECOGNIZE, false);

        if (mCardOrientationVertical) {
            mFrameOrientation = ORIENTATION_PORTRAIT;
        } else {
            mFrameOrientation = getIntent().getIntExtra(EXTRA_SCAN_ORIENTATION, ORIENTATION_PORTRAIT);
        }
    }

    /**
     * 初始化界面的方向
     */
    private void initOrientation() {
        switch (mFrameOrientation) {
            case ORIENTATION_PORTRAIT:
            default:
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                break;
            case ORIENTATION_LANDSCAPE_LEFT:
                // 横向左
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                break;
            case ORIENTATION_PORTRAIT_UPSIDE_DOWN:
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
                break;
            case ORIENTATION_LANDSCAPE_RIGHT:
                // 横向右
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
                break;
        }

    }

    /**
     * 创建OCR扫描类
     */
    protected void createCardScan() {
        int previewTimeGaps = getIntent().getIntExtra(EXTRA_PREVIEW_TIME_GAPS, -1);
        String previewStoragePath = getIntent().getStringExtra(EXTRA_PREVIEW_STOREAGE_PATH);
        int savedNum = getIntent().getIntExtra(EXTRA_PREVIEW_SAVED_NUM, 3);

        mCardScanner = initCardScanner(this, mFrameOrientation, mCardOrientationVertical);
        mCardScanner.setCardScanListener(this);
        mCardScanner.setIsStartAutoFocus(mScanIsAutoFocus);
        mCardScanner.init();
        mCardScanner.setIsInFrame(mIsInFrame);
        mCardScanner.setScanTimeOut(mScanTimeOut);
        mCardScanner.setRotation(mCardPresenter.getRotation(this));

        mCardScanner.prepareScanner();
        mCardScanner.setPreviewInfo(previewTimeGaps, previewStoragePath, savedNum);
        // 判断是自动识别还是拍照识别
        mCardScanner.setIsNeedAutoRecognize(!mScanIsManualRecognize);

        mCardScanRect = new Rect();
    }

    /**
     * 暂停OCR扫描
     */
    protected void pauseCardScan() {
        if (mCardScanner != null) {
            mCardScanner.setCameraRelease(false);
            mCardScanner.pauseScanning();
        }
    }

    /**
     * 释放OCR扫描
     */
    private void releaseCardScan() {
        if (mCardScanner != null) {
            mCardScanner.endScanning();
            mCardScanner = null;
        }
    }

    /**
     * 重新开始OCR扫描
     */
    private boolean restartCardScan() {
        if (mPlytPreview == null || mCardScanner == null) {
            return false;
        }

        boolean isSuccess = mCardScanner.resumeScanning(mPlytPreview.getSurfaceHolder());
        mCardScanner.setCameraRelease(false);
        initPreviewView();
        return isSuccess;
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (!restartCardScan()) {
            MXLog.e(TAG, "无法打开摄像头");
            setResultAndFinish(RESULT_CAMERA_NOT_AVAILABLE, null);
        }
        initLightManager();
    }


    @Override
    protected void onPause() {
        MXLog.e(TAG, "onPause");
        pauseCardScan();
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        MXLog.e(TAG, "onDestroy");
        mOverlay = null;
        releaseCardScan();
        super.onDestroy();
        mPlytPreview = null;
        destroyLightManager();
    }

    private void handleGeneralExceptionError(Exception e) {
        MXLog.e(Util.PUBLIC_LOG_TAG, "发生未知异常，请与我们联系 https://www.linkface.cn", e);
    }

    /**
     * 创建扫描覆盖层
     *
     * @return Overlay View
     */
    protected View createOverlayView() {
        OverlayView overlay = new OverlayView(this, null);
        overlay.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        if (getIntent() != null) {
            String scanInstructions = getIntent().getStringExtra(EXTRA_SCAN_TIPS);
            if (scanInstructions != null) {
                overlay.setScanText(scanInstructions);
            }
        }
        overlay.setBorderColor(mScanRectColor);
        overlay.setScanBackGroundColor(mBackGroundColor);
        Bitmap horizontalScanLineBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_scan_line);
        overlay.setScanLineHorizontalBitmap(horizontalScanLineBitmap);
        Matrix matrix = new Matrix();
        matrix.postRotate(90);
        Bitmap verticalScanLineBitmap = Bitmap.createBitmap(horizontalScanLineBitmap, 0, 0,
                horizontalScanLineBitmap.getWidth(), horizontalScanLineBitmap.getHeight(), matrix, false);
        overlay.setScanLineVerticalBitmap(verticalScanLineBitmap);
        overlay.setScanOrientation(mCardOrientationVertical ? OverlayView.SCAN_ORIENTATION_VERTICAL :
                OverlayView.SCAN_ORIENTATION_HORIZONTAL);
        overlay.switchScan(mIsStartScanLine);
        return overlay;
    }

    /**
     * 是否开启扫描光标
     *
     * @param isStartScan
     */
    protected void switchScanStatus(boolean isStartScan) {
        OverlayView overlayView = getOverlayView();
        if (overlayView != null) {
            overlayView.switchScan(isStartScan);
        }
    }

    /**
     * 获取取景框的Rect
     *
     * @return 扫描框的Rect
     */
    protected Rect getCardScanFrame() {
        return mCardScanRect;
    }

    /**
     * @return
     */
    public int getFrameOrientation() {
        return mFrameOrientation;
    }

    public void onTextUpdate(final String text, final int textColor) {
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                if (mOverlay instanceof OverlayView) {
                    ((OverlayView) mOverlay).updateTextAndColor(text, textColor);
                }
            }
        });
    }

    protected void resumeScanning() {
        if (mCardScanner != null) {
            mCardScanner.resumeScanning(mPlytPreview.getSurfaceHolder());
        }
    }

    private OverlayView getOverlayView() {
        OverlayView overlayView = null;
        if (mOverlay instanceof OverlayView) {
            overlayView = (OverlayView) mOverlay;
        }
        return overlayView;
    }

    @Override
    public void onCardDetected(com.moxie.ocr.ocr.base.Card card, Bitmap cameraApertureBitmap, Bitmap cropCardBitmap) {



        playVibrator();
        pauseCardScan();

        goToResultActivity(card, cameraApertureBitmap, cropCardBitmap,IDCardRecognizer.Mode.FRONT);
    }



    protected void goToResultActivity(com.moxie.ocr.ocr.base.Card card, Bitmap cameraApertureBitmap, Bitmap cropCardBitmap, IDCardRecognizer.Mode mode) {
        if(card == null) {
            // 未能识别时
            MXWindowToast wToast = new MXWindowToast();
            wToast.makeToast(CardActivity.this, "识别失败！", 500).show();
            return;
        }

        // 识别成功 则需要关闭相机
        pauseCardScan();

        Intent dataIntent = new Intent();

        MXOCRResult result= (MXOCRResult) card;

        //设置带边框的图片
        if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_CARD_IMAGE, true)) {
            ByteArrayOutputStream scaledCardBytes = new ByteArrayOutputStream();
            cameraApertureBitmap.compress(Bitmap.CompressFormat.JPEG, 80, scaledCardBytes);
            switch (mode){
                case FRONT:
                    result.setCameraApertureImage(scaledCardBytes.toByteArray());
                    break;
                case BACK:
                    result.setCameraApertureImage(scaledCardBytes.toByteArray());
                    break;
            }
        }

        //返回裁剪图
        if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_CARD_IMAGE_RECTIFIED, true)
                && cropCardBitmap != null) {
            ByteArrayOutputStream scaledCardBytesRectified = new ByteArrayOutputStream();
            cropCardBitmap.compress(Bitmap.CompressFormat.JPEG, 80, scaledCardBytesRectified);
//            dataIntent.putExtra(EXTRA_CARD_IMAGE_RECTIFIED,scaledCardBytesRectified.toByteArray());
            switch (mode){
                case FRONT:
                    result.setCropImage(scaledCardBytesRectified.toByteArray());
                    break;
                case BACK:
                    result.setCropImage(scaledCardBytesRectified.toByteArray());
                    break;
            }
        }

        // 返回头像裁剪图
        if (cropCardBitmap!=null && mode==IDCardRecognizer.Mode.FRONT){
            ByteArrayOutputStream scaledCardBytesRectified = new ByteArrayOutputStream();
            int height = cropCardBitmap.getHeight();
            int width = cropCardBitmap.getWidth();
            Bitmap avatar = Bitmap.createBitmap(cropCardBitmap, width / 8 * 5, height / 7, width / 3, height / 5 * 3);
            avatar.compress(Bitmap.CompressFormat.JPEG, 80, scaledCardBytesRectified);
            result.setCropFaceImage(scaledCardBytesRectified.toByteArray());
        }


        dataIntent.putExtra(EXTRA_SCAN_RESULT,result);

        setResultAndFinish(RESULT_CARD_INFO, dataIntent);
    }


    /**
     * 播放震动
     */
    protected void playVibrator() {
        if (mCardPresenter != null) {
            mCardPresenter.playVibrator(this);
        }
    }

    /**
     * 设置识别的方向
     */
    protected boolean getCardOrientationVertical() {
        return mCardOrientationVertical;
    }

    /**
     * 设置是否全卡在扫描框内才能识别
     * */
    protected boolean getScanIsInFrame() {
        return mIsInFrame;
    }

    /**
     * 设置识别的方向
     *
     * @param cardOrientationVertical
     */
    protected void setCardOrientationVertical(boolean cardOrientationVertical) {
        mCardOrientationVertical = cardOrientationVertical;
        CardScanner cardScanner = getCardScanner();
        if (cardScanner != null) {
            cardScanner.setCardOrientationVertical(mCardOrientationVertical);
        }
    }


    protected CardScanner getCardScanner() {
        return mCardScanner;
    }

    protected abstract CardScanner initCardScanner(Context context, int currentFrameOrientation, boolean isVertical);

    void setResultAndFinish(final int resultCode, final Intent data) {
        setResult(resultCode, data);
        finish();
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        MXLog.i(TAG, "landscapeTest", "surfaceCreated");
        initOverlayView();
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        MXLog.i(TAG, "landscapeTest", "surfaceChanged");
        clearOverlayView();
        initOverlayView();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        MXLog.i(TAG, "landscapeTest", "surfaceDestroyed");
        clearOverlayView();
    }

    @Override
    public void initFail() {
        setResultAndFinish(RESULT_RECOGNIZER_INIT_FAILED, null);
    }

    @Override
    public void scanTimeOut() {
        setResultAndFinish(RESULT_RECOGNIZER_FAIL_SCAN_TIME_OUT, null);
    }

    @Override
    public void onLightChange(float light) {
        if (light <= 2 && mIsCanStartFlashWhenLightChange) {
            onSwitchCameraFlashLight(true);
            if (mCbFlashLight != null) {
                mCbFlashLight.setChecked(true);
            }
        }
    }


    public static Bitmap resizeImage(Bitmap bitmap, int w, int h) {
        Bitmap BitmapOrg = bitmap;
        int width = BitmapOrg.getWidth();
        int height = BitmapOrg.getHeight();
        int newWidth = w;
        int newHeight = h;

        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;

        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);

        Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width,
                height, matrix, true);
        return resizedBitmap;
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        setResult(RESULT_CANCELED);
        finish();
    }
}
